from . import homework_blueprint
from ..utils.response_util import *
from ..utils.exception import APIException
from ..utils.error_code import *
from ..models import db, User, Course, StudentCourse, Homework, StudentHomework
from ..utils.check import *
from ..utils.score_calc import *

from flask import request, session, send_file
import json
import pandas as pd

from io import BytesIO
import datetime
from math import ceil


@homework_blueprint.route("/", methods=["GET", "POST"])
def homework_main():
    return "Homework"


@homework_blueprint.errorhandler(APIException)
def homework_error(e):
    return APIException.to_dict(e)


@homework_blueprint.route("/list", methods=["POST"])
def homework_list():
    """
    获得 homework 列表
    :return:
    """
    try:
        current_page = int(request.args.get("currentPage"))
    except:
        current_page = 1
    data_per_page = 10
    username = session.get("username")
    own_homework = None
    homeworks = Homework.query.filter_by(homework_visibility=True).order_by(-Homework.create_time).all()
    r = list()

    # 用户权限 >= 教师: 查看自己添加的 homework
    if username is not None:
        user = User.query.filter_by(username=username).first()
        if user is not None:
            user_type = user.user_type
            if 2 <= user_type < 4:
                own_homework = Homework.query.filter_by(homework_add_user_id=username).order_by(-Homework.create_time).all()
            elif user_type == 4:
                own_homework = Homework.query.order_by(-Homework.create_time).all()

    if own_homework is not None:
        homeworks = list(set(own_homework).union(set(homeworks)))

    list_len = len(homeworks)
    for homework in homeworks:
        tmp = dict()
        tmp["homework_id"] = homework.homework_id
        tmp["homework_title"] = homework.homework_title
        tmp["start_time"] = str(homework.start_time)
        tmp["end_time"] = str(homework.end_time)
        tmp["state"] = "Open" if homework.end_time > datetime.datetime.now() > homework.start_time else "Ended"
        tmp["type"] = "public" if homework.homework_visibility == 1 else "private"

        r.append(tmp)

    max_page_num = ceil(list_len / data_per_page)
    ret = {
        "currentPage": current_page,
        "maxPageNum": max_page_num,
        "num": list_len,
        "list": r[data_per_page * (current_page - 1): data_per_page * current_page]
    }
    
    return response(200, "Query Homework List Success", ret)


@homework_blueprint.route("/add", methods=["POST"])
@user_is_login
@check_user_type_2
def homework_add():
    """
    添加 homework
    :return:
    """
    data = get_data()
    homework_title = data.get("homeworkTitle")
    homework_visibility = data.get("homeworkVisibility")
    start_time = data.get("startTime")
    end_time = data.get("endTime")
    homework_question = data.get("homeworkQuestion")
    course_id = data.get("courseId")
    username = session.get("username")

    homework = Homework(homework_title, homework_visibility, start_time,
                        end_time, json.dumps(homework_question), username, course_id)
    try:
        db.session.add(homework)
        db.session.commit()
    except:
        db.session.rollback()
        raise APIException(ADD_ERROR)
    finally:
        db.session.close()

    return response(200, "Add Homework Success", {})


@homework_blueprint.route("/delete", methods=["POST"])
@user_is_login
@check_user_type_2
def homework_delete():
    """
    删除 homework
    :return:
    """
    data = get_data()
    homework_id = data.get("homeworkId")
    username = session.get("username")
    user = User.query.filter_by(username=username).first()

    homework = Homework.query.filter_by(homework_id=homework_id).first()
    if homework is None:
        raise APIException(NO_HOMEWORK_EXISTS)
    if user.user_type <= 3 and homework.homework_add_user_id != int(username):
        raise APIException(USERNAME_ILLEGAL)

    res = Homework.query.filter_by(homework_id=homework_id).delete()
    db.session.commit()
    db.session.close()

    if res == 1:
        return response(200, "Delete Homework Success", {})
    else:
        raise APIException(DELETE_ERROR)


@homework_blueprint.route("/update", methods=["POST"], endpoint="homeworkUpdate")
@user_is_login
@check_user_type_2
def homework_update():
    """
    修改作业
    :return:
    """
    data = get_data()
    username = session.get("username")
    homework_id = data.get("homeworkId")
    homework_visibility = data.get("homeworkVisibility")
    start_time = data.get("startTime")
    end_time = data.get("endTime")
    homework_question = data.get("homeworkQuestion")
    homework_course = data.get("courseId")
    new_data = dict()

    homework = Homework.query.filter(Homework.homework_id == homework_id).first()
    user = User.query.filter_by(username=username).first()
    if homework is None:
        raise APIException(NO_HOMEWORK_EXISTS)
    if homework.homework_add_user_id != int(username) and user.user_type < 4:
        raise APIException(INSUFFICIENT_USER_PERMISSION)
    # 修改 homework 内容
    if start_time is not None:
        new_data["start_time"] = start_time
    if end_time is not None:
        new_data["end_time"] = end_time
    if homework_question is not None:
        new_data["homework_question"] = json.dumps(homework_question)
    if homework_course is not None:
        new_data["homework_course"] = homework_course
    if homework_visibility is not None:
        new_data["homework_visibility"] = homework_visibility

    res = Homework.query.filter_by(homework_id=homework_id).update(new_data)
    db.session.commit()
    db.session.close()

    if res == 1:
        return response(200, "Update Homework Success", {"homeworkId": homework_id})
    else:
        raise APIException(UPDATE_ERROR)


@homework_blueprint.route("/search", methods=["POST"], endpoint="homeworkSearch")
@user_is_login
def homework_search():
    """
    查看单个 homework
    :return:
    """
    data = get_data()
    homework_id = data.get("homeworkId")
    homework = Homework.query.filter_by(homework_id=homework_id).first()
    username = session.get("username")
    user = User.query.filter_by(username=username).limit(1).first()

    if homework is None:
        raise APIException(NO_HOMEWORK_EXISTS)
    homework_course = homework.homework_course
    if not is_student_belongs_course(homework_course):
        raise APIException(USERNAME_ILLEGAL)
    if user.user_type == 1 and (homework.end_time <= datetime.datetime.now() or datetime.datetime.now() <= homework.start_time):
        raise APIException(HOMEWORK_HAS_ALREADY_CLOSED)
    if user.user_type == 1 and homework.status is False:
        raise APIException(NO_HOMEWORK_EXISTS)

    r = dict()
    r["homework_id"] = homework.homework_id
    r["homework_title"] = homework.homework_title
    r["start_time"] = str(homework.start_time)
    r["end_time"] = str(homework.end_time)
    r["homework_visibility"] = homework.homework_visibility
    r["status"] = "Open" if homework.end_time >= datetime.datetime.now() >= homework.start_time else "Ended"
    r["questions"] = json.loads(homework.homework_question)
    r["course_id"] = homework.homework_course
    r["homework_status"] = homework.status

    return response(200, "Query Homework Success", r)


@homework_blueprint.route("/score/search", methods=["POST"])
@user_is_login
def homework_score_search():
    """
    查看当前作业的成绩
    :return:
    """
    data = get_data()
    username = session.get("username")
    homework_id = data.get("homeworkId")
    user = User.query.filter(User.username == username).first()
    homework = Homework.query.filter(Homework.homework_id == homework_id).first()

    r = list()

    if homework is None:
        raise APIException(NO_HOMEWORK_EXISTS)

    if user.user_type > 1:
        student_homeworks = StudentHomework.query.filter_by(homework_id=homework_id).all()
        for student_homework in student_homeworks:
            score = student_homework.score
            if score is None or score == 0:
                score = score_submit_homework(homework_id, student_homework.student_id)
            tmp = dict()
            tmp["studentHomeworkId"] = student_homework.student_homework_id
            tmp["username"] = student_homework.student_id
            tmp["homework_id"] = student_homework.homework_id
            tmp["score"] = student_homework.score
            r.append(tmp)
    elif user.user_type == 1:
        student_homework = StudentHomework.query.filter_by(student_id=username, homework_id=homework_id).first()
        score = student_homework.score
        if student_homework is None:
            raise APIException(SEARCH_ERROR)
        if score is None or score == 0:
            score_submit_homework(homework_id, student_homework.student_id)
        tmp = dict()
        tmp["studentHomeworkId"] = student_homework.student_homework_id
        tmp["username"] = student_homework.student_id
        tmp["homework_id"] = student_homework.homework_id
        tmp["score"] = student_homework.score
        r.append(tmp)

    return response(200, "Query Score Success", r)


@homework_blueprint.route("/score/export", methods=["POST"])
@user_is_login
@check_user_type_2
def homework_export():
    """
    导出作业成绩
    :return:
    """
    data = get_data()
    username = session.get("username")
    homework_id = data.get("homeworkId")
    user = User.query.filter(User.username == username).first()
    homework = Homework.query.filter(Homework.homework_id == homework_id).first()
    r = {
        "studentHomeworkId": [],
        "username": [],
        "score": []
    }

    if homework is None:
        raise APIException(NO_HOMEWORK_EXISTS)

    if 2 == user.user_type and homework.homework_add_user_id != int(username):
        raise APIException(USERNAME_ILLEGAL)
    else:
        student_homeworks = StudentHomework.query.filter(StudentHomework.homework_id == homework_id).all()
        for student_homework in student_homeworks:
            r["studentHomeworkId"].append(student_homework.student_homework_id)
            r["username"].append(student_homework.student_id)
            r["score"].append(student_homework.score)

    result = pd.DataFrame(r)

    output = BytesIO()
    writer = pd.ExcelWriter(output, engine='xlsxwriter')

    result.to_excel(writer, startrow=0, merge_cells=False, sheet_name="Result")

    workbook = writer.book
    my_format = workbook.add_format()
    my_format.set_bg_color('#eeeeee')

    writer.close()
    output.seek(0)

    return send_file(output, attachment_filename="result.xlsx", as_attachment=True)


@homework_blueprint.route("/score/update", methods=["POST"])
@user_is_login
@check_user_type_2
def homework_update():
    """
    修改作业成绩
    :return:
    """
    data = get_data()
    if data is None:
        data = request.form
    student_homework_id = data.get("studentHomeworkId")
    score = data.get("score")

    if score is None:
        raise APIException(NO_DATA_FOUND)
    student_homework = StudentHomework.query.filter(StudentHomework.student_homework_id == student_homework_id).first()
    if student_homework is None:
        raise APIException(NO_DATA_FOUND)

    res = StudentHomework.query.filter(StudentHomework.student_homework_id == student_homework_id).update({"score": score})
    db.session.commit()
    db.session.close()
    if res == 1:
        return response(200, "Update Score Success", {})
    else:
        raise APIException(UPDATE_ERROR)


@homework_blueprint.route("/answer", methods=["GET"], endpoint="homeworkAnswer")
def homework_answer():
    """
    查看作业答案
    :return:
    """
    # TODO


@homework_blueprint.route("/submit", methods=["POST"])
def homework_submit():
    pass


@homework_blueprint.route("/list/course", methods=["POST"])
def homework_list_course():
    """
    获得 homework 列表
    :return:
    """
    try:
        current_page = int(request.args.get("currentPage"))
    except:
        current_page = 1
    data = get_data()
    homework_course = data.get("courseId")
    data_per_page = 10
    username = session.get("username")
    own_homework = None
    homeworks = Homework.query.filter_by(homework_visibility=True, homework_course=homework_course).order_by(-Homework.create_time).all()
    r = list()

    # 用户权限 >= 教师: 查看自己添加的 homework
    if username is not None:
        user = User.query.filter_by(username=username).first()
        if user is not None:
            user_type = user.user_type
            if 2 <= user_type < 4:
                own_homework = Homework.query.filter_by(homework_add_user_id=username, homework_course=homework_course).order_by(-Homework.create_time).all()
            elif user_type == 4:
                own_homework = Homework.query.filter_by(homework_course=homework_course).order_by(-Homework.create_time).all()

    if own_homework is not None:
        homeworks = list(set(own_homework).union(set(homeworks)))

    list_len = len(homeworks)
    for homework in homeworks:
        tmp = dict()
        tmp["homework_id"] = homework.homework_id
        tmp["homework_title"] = homework.homework_title
        tmp["start_time"] = str(homework.start_time)
        tmp["end_time"] = str(homework.end_time)
        tmp["state"] = "Open" if homework.end_time > datetime.datetime.now() > homework.start_time else "Ended"
        tmp["type"] = "public" if homework.homework_visibility == 1 else "private"

        r.append(tmp)

    max_page_num = ceil(list_len / data_per_page)
    ret = {
        "currentPage": current_page,
        "maxPageNum": max_page_num,
        "num": list_len,
        "list": r[data_per_page * (current_page - 1): data_per_page * current_page]
    }
    
    return response(200, "Query Homework List Success", ret)
